<script setup lang="ts">
import { computed, nextTick, watch } from 'vue'
import MarkdownIt from 'markdown-it'
import hljs from 'highlight.js/lib/core'

import javascript from 'highlight.js/lib/languages/javascript'
import typescript from 'highlight.js/lib/languages/typescript'
import json from 'highlight.js/lib/languages/json'
import yaml from 'highlight.js/lib/languages/yaml'
import bash from 'highlight.js/lib/languages/bash'
import shell from 'highlight.js/lib/languages/shell'
import python from 'highlight.js/lib/languages/python'
import java from 'highlight.js/lib/languages/java'
import go from 'highlight.js/lib/languages/go'
import csharp from 'highlight.js/lib/languages/csharp'
import xml from 'highlight.js/lib/languages/xml'
import css from 'highlight.js/lib/languages/css'
import sql from 'highlight.js/lib/languages/sql'

const languages: Record<string, hljs.LanguageFn> = {
  javascript,
  typescript,
  json,
  yaml,
  bash,
  shell,
  python,
  java,
  go,
  csharp,
  xml,
  html: xml,
  css,
  sql,
}

Object.entries(languages).forEach(([name, loader]) => {
  if (!hljs.getLanguage(name)) {
    hljs.registerLanguage(name, loader)
  }
})

const props = defineProps<{
  content?: string
}>()

const md = new MarkdownIt({
  html: true,
  linkify: true,
  typographer: true,
  highlight(code: string, language: string) {
    if (language && hljs.getLanguage(language)) {
      const { value } = hljs.highlight(code, { language, ignoreIllegals: true })
      return `<pre class="hljs"><code class="language-${language}">${value}</code></pre>`
    }
    return `<pre class="hljs"><code>${md.utils.escapeHtml(code)}</code></pre>`
  },
})

const renderedHtml = computed(() => md.render(props.content ?? ''))

const applyHighlight = async () => {
  await nextTick()
  hljs.highlightAll()
}

watch(renderedHtml, applyHighlight, { immediate: true })
</script>

<template>
  <div class="md-preview" v-html="renderedHtml" />
</template>

<style scoped lang="scss">
.md-preview {
  padding: 12px;
  line-height: 1.7;
  color: #1f2933;

  :deep(h1),
  :deep(h2),
  :deep(h3) {
    font-weight: 600;
    margin: 1.2em 0 0.6em;
  }

  :deep(p),
  :deep(ul),
  :deep(ol),
  :deep(pre) {
    margin: 0.6em 0;
  }

  :deep(pre) {
    background: #f6f8fa;
    border-radius: 6px;
    padding: 12px;
    overflow-x: auto;
  }

  :deep(code) {
    font-family: 'Fira Code', Menlo, Monaco, Consolas, 'Courier New', monospace;
    font-size: 13px;
  }
}
</style>